// 类型定义
interface SwitchMetaItem {
  id: number;
  alias?: string;
  factor?: string;
  jsonSchema?: string;
}

// 校验结果接口
export interface ValidationResult {
  isValid: boolean;
  errors: ValidationError[];
}

export interface ValidationError {
  path: string;
  message: string;
  factorId?: number;
  factorName?: string;
}

// 根据JSON Schema校验单个config值
const validateConfigBySchema = (
  config: any,
  jsonSchema: any,
  factorId: number,
  factorName: string,
  path: string = ''
): ValidationError[] => {
  const errors: ValidationError[] = [];

  if (!jsonSchema || typeof jsonSchema !== 'object') {
    return errors;
  }

  const { type, required, properties } = jsonSchema;

  // 校验必填字段
  if (required && Array.isArray(required)) {
    required.forEach((field: string) => {
      if (!config || config[field] === undefined || config[field] === null || config[field] === '') {
        errors.push({
          path: path ? `${path}.${field}` : field,
          message: `字段 "${field}" 是必填项`,
          factorId,
          factorName
        });
      }
    });
  }

  // 校验类型
  if (type && config !== undefined && config !== null) {
    switch (type) {
      case 'object':
        if (typeof config !== 'object' || Array.isArray(config)) {
          errors.push({
            path,
            message: `期望类型为对象，实际类型为 ${Array.isArray(config) ? 'array' : typeof config}`,
            factorId,
            factorName
          });
        } else if (properties) {
          // 递归校验对象属性
          Object.keys(properties).forEach(key => {
            const subErrors = validateConfigBySchema(
              config[key],
              properties[key],
              factorId,
              factorName,
              path ? `${path}.${key}` : key
            );
            errors.push(...subErrors);
          });
        }
        break;
      case 'array':
        if (!Array.isArray(config)) {
          errors.push({
            path,
            message: `期望类型为数组，实际类型为 ${typeof config}`,
            factorId,
            factorName
          });
        }
        break;
      case 'string':
        if (typeof config !== 'string') {
          errors.push({
            path,
            message: `期望类型为字符串，实际类型为 ${typeof config}`,
            factorId,
            factorName
          });
        }
        break;
      case 'number':
        if (typeof config !== 'number') {
          errors.push({
            path,
            message: `期望类型为数字，实际类型为 ${typeof config}`,
            factorId,
            factorName
          });
        }
        break;
      case 'boolean':
        if (typeof config !== 'boolean') {
          errors.push({
            path,
            message: `期望类型为布尔值，实际类型为 ${typeof config}`,
            factorId,
            factorName
          });
        }
        break;
    }
  }

  return errors;
};

// 递归校验规则树
const validateRuleNode = (
  node: any,
  factorOptions: SwitchMetaItem[],
  path: string = 'root'
): ValidationError[] => {
  const errors: ValidationError[] = [];

  if (!node) {
    return errors;
  }

  // 判断节点类型
  const isGroupNode = node.nodeType && (node.nodeType === 'AND' || node.nodeType === 'OR');
  const isFactorNode = !node.nodeType;

  // 如果没有nodeType，必须是因子节点
  if (isFactorNode) {
    // 因子节点的基本校验
    if (!node.id || node.id === 0) {
      errors.push({
        path,
        message: '因子节点的ID不能为空或0',
        factorId: node.id,
        factorName: node.factor
      });
    }

    if (!node.factor || node.factor === '') {
      errors.push({
        path,
        message: '因子节点的factor不能为空',
        factorId: node.id,
        factorName: node.factor
      });
    }

    if (node.config === undefined || node.config === null || node.config === '') {
      errors.push({
        path,
        message: '因子节点的config不能为空',
        factorId: node.id,
        factorName: node.factor
      });
    }
  }

  // 如果是因子节点且基本信息有效
  if (isFactorNode && node.id && node.factor) {
    const factor = factorOptions.find(f => f.id === node.id);
    
    if (!factor) {
      errors.push({
        path,
        message: `找不到ID为 ${node.id} 的因子配置`,
        factorId: node.id,
        factorName: node.factor
      });
      return errors;
    }

    // 解析JSON Schema
    let jsonSchema;
    try {
      jsonSchema = JSON.parse(factor.jsonSchema || '{}');
    } catch (error) {
      errors.push({
        path,
        message: `因子 "${factor.alias}" 的JSON Schema格式错误`,
        factorId: node.id,
        factorName: node.factor
      });
      return errors;
    }

    // 校验config
    const configErrors = validateConfigBySchema(
      node.config,
      jsonSchema,
      node.id,
      factor.alias || node.factor,
      `${path}.config`
    );
    errors.push(...configErrors);
  }

  // 如果是组节点
  if (isGroupNode) {
    // 组节点必须有children
    if (!node.children || !Array.isArray(node.children) || node.children.length === 0) {
      errors.push({
        path,
        message: `组节点 "${node.nodeType}" 必须包含至少一个子节点`,
        factorId: node.id,
        factorName: node.factor
      });
    } else {
      // 递归校验子节点
      node.children.forEach((child: any, index: number) => {
        const childErrors = validateRuleNode(
          child,
          factorOptions,
          `${path}.children[${index}]`
        );
        errors.push(...childErrors);
      });
    }
  }

  // 如果既不是组节点也不是因子节点
  if (!isGroupNode && !isFactorNode) {
    errors.push({
      path,
      message: '节点必须是组节点（有nodeType）或因子节点（无nodeType）',
      factorId: node.id,
      factorName: node.factor
    });
  }

  return errors;
};

// 主校验函数
export const validateParsedRule = (
  parsedRule: any,
  factorOptions: SwitchMetaItem[]
): ValidationResult => {
  const errors = validateRuleNode(parsedRule, factorOptions);
  
  return {
    isValid: errors.length === 0,
    errors
  };
};

// 格式化错误信息
export const formatValidationErrors = (errors: ValidationError[]): string => {
  if (errors.length === 0) {
    return '校验通过';
  }

  return errors.map(error => {
    const factorInfo = error.factorName ? `[${error.factorName}] ` : '';
    return `${factorInfo}${error.message} (路径: ${error.path})`;
  }).join('\n');
};
